package com.engine.controller;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import com.engine.pattern.grid.Grid;
import com.engine.pattern.pawn.Metabolite;
import com.engine.pattern.pawn.Pawn;
import com.engine.pattern.pawn.Phospholipide;
import com.engine.pattern.pawn.Proteine;
import com.engine.pattern.player.Computer;
import com.engine.pattern.player.Human;
import com.engine.pattern.player.Player;
import com.engine.view.DisplayColored;

/**
 * @author jonathan
 * @author fabienne
 */
public final class Controller
{

	/**
	 * 
	 */
	private static ArrayList<Player>	players			= new ArrayList<Player>();
	/**
	 * 
	 */
	private static DisplayColored		display			= new DisplayColored();
	/**
	 * 
	 */
	private static Grid					grid			= new Grid();
	/**
	 * 
	 */
	private static Boolean				gameContinue	= true;
	/**
	 * 
	 */
	private static Integer				mode			= 0;

	/**
	 * 
	 */
	public static void start()
	{
		Boolean badPlayerNb = true;
		Integer humanFn = 0;
		Integer computerFn = 0;

		while (mode < 1 || mode > 2)
		{
			mode = display.askWhichMode();
		}

		while (badPlayerNb)
		{
			Boolean nullValue = true;
			while (nullValue)
			{
				humanFn = display.askHowManyHuman();
				if (humanFn == null)
				{
					nullValue = true;
				}
				else
				{
					nullValue = false;
				}
			}

			nullValue = true;
			while (nullValue)
			{
				computerFn = display.askHowManyComputer();
				if (computerFn == null)
				{
					nullValue = true;
				}
				else
				{
					nullValue = false;
				}
			}

			if (humanFn + computerFn > 4)
			{
				badPlayerNb = true;
				display.badPlayerNb();
			}
			else
			{
				badPlayerNb = false;
			}
		}

		if (humanFn == 0 && computerFn == 0)
		{
			display.noPlayer();
			gameContinue = false;
		}
		else
		{
			if (humanFn > 0)
			{
				createHumanPlayer(humanFn);
			}
			if (computerFn > 0)
			{
				createComputerPlayer(computerFn);
			}
		}

		while (gameContinue)
		{
			Iterator<Player> iterator = players.iterator();
			initialiseGrid();

			while (iterator.hasNext() && gameContinue)
			{
				Boolean badChoice = true;
				Player player = iterator.next();
				display.show(grid.getGrid());
				while (badChoice)
				{
					// Affichage choix du metabolite
					badChoice = moveMetabolite(player);
					if (badChoice)
					{
						display.invalidChoice();
					}
				}
				display.show(grid.getGrid());
				badChoice = true;
				while (badChoice)
				{
					// Affichage choix proteine ou phospholipide
					badChoice = moveProtPhos(player);
					if (badChoice)
					{
						display.invalidChoice();
					}

				}
				if (player.getScore() >= 15)
				{
					badChoice = false;
					gameContinue = false;
				}
			}
		}
		printAllScore();
		searchMaxScore();
	}

	/**
	 * 
	 */
	private static void initialiseGrid()
	{
		Iterator<Player> iterator = players.iterator();
		Boolean badPosition = true;
		Integer higher = 30;
		Integer lower = 0;
		// Put Metabolite
		for (Integer j = 0; j < 20; j++)
		{
			badPosition = true;
			while (badPosition)
			{
				Integer x = (int) (Math.random() * (higher - lower) + lower);
				Integer y = (int) (Math.random() * (higher - lower) + lower);
				Metabolite metabolite = new Metabolite();
				badPosition = initPlace(x, y, metabolite, 0);
			}
		}
		if (mode == 2)
			display.show(grid.getGrid());
		while (iterator.hasNext())
		{
			Player player = iterator.next();
			// Put protein
			for (Integer i = 0; i < 5; i++)
			{
				badPosition = true;
				while (badPosition)
				{
					if (mode == 1)
					{
						Integer x = (int) (Math.random() * (higher - lower) + lower);
						Integer y = (int) (Math.random() * (higher - lower) + lower);
						Proteine proteine = new Proteine(i + 1, player
								.getName());
						badPosition = initPlace(x, y, proteine, player
								.getPlayerId());
					}
					else
					{
						Proteine proteine = new Proteine(i + 1, player
								.getName());
						Integer x = null;
						Integer y = null;
						while (x == null)
						{
							x = display.askAxis(player.getName(), proteine
									.getClass().getName(), "x", player
									.getPlayerId());
						}
						while (y == null)
						{
							y = display.askAxis(player.getName(), proteine
									.getClass().getName(), "y", player
									.getPlayerId());
						}
						badPosition = initPlace(x, y, proteine, player
								.getPlayerId());
						display.show(grid.getGrid());
					}
				}

			}
			// Put Phospholipid
			for (Integer j = 0; j < 20; j++)
			{
				badPosition = true;
				while (badPosition)
				{
					if (mode == 1)
					{
						Integer x = (int) (Math.random() * (higher - lower) + lower);
						Integer y = (int) (Math.random() * (higher - lower) + lower);
						Phospholipide phospholipide = new Phospholipide(player
								.getName());
						badPosition = initPlace(x, y, phospholipide, player
								.getPlayerId());
					}
					else
					{
						Phospholipide phospholipide = new Phospholipide(player
								.getName());
						Integer x = display.askAxis(player.getName(),
								phospholipide.getClass().getName(), "x", player
										.getPlayerId());
						Integer y = display.askAxis(player.getName(),
								phospholipide.getClass().getName(), "y", player
										.getPlayerId());
						badPosition = initPlace(x, y, phospholipide, player
								.getPlayerId());
						display.show(grid.getGrid());
					}

				}
			}
		}
	}

	/**
	 * @param x
	 * @param y
	 * @param pawn
	 * @param playerId
	 * @return
	 */
	private static boolean initPlace(int x, int y, Pawn pawn, Integer playerId)
	{
		if (grid.getPawn(x, y) == null)
		{
			grid.addPawn(pawn, x, y);
			pawn.setPlayerId(playerId);
			return false;
		}
		else
		{
			display.invalidChoice();
			return true;
		}
	}

	/**
	 * @param player
	 * @return
	 */
	private static Boolean moveMetabolite(Player player)
	{
		Integer c1[] = new Integer[2];
		while (c1[0] == null || c1[1] == null)
		{
			c1 = display.askWhichPawnMove(player.getName(), player
					.getPlayerId(), "metabolite");
		}
		Boolean wrongCoordinated = true;
		if (grid.getPawn(c1) != null
				&& grid.getPawn(c1).getClass().getName().equals(
						"com.engine.pattern.pawn.Metabolite"))
		{
			Pawn pawn = grid.getPawn(c1);
			Boolean continueMove = true;
			Integer moveLeft = pawn.getMoveFn();
			while (continueMove)
			{
				Integer choice = null;
				while (choice == null)
				{
					choice = display.chooseAnAction(moveLeft);
				}
				switch (choice)
				{
					case 1:
					{
						Integer[] c2 = new Integer[2];
						while (c2[0] == null || c2[1] == null)
						{
							c2 = display.askWherePawnMove(player.getName(),
									player.getPlayerId());
						}
						ArrayList<Integer[]> possibleCells = calculPossibleCells(
								pawn, c1);
						Boolean contains = false;
						Iterator<Integer[]> cell = possibleCells.iterator();
						while (cell.hasNext())
						{
							Integer[] a = cell.next();
							if (a[0] == c2[0])
							{
								if (a[1] == c2[1])
								{
									contains = true;
									break;
								}
							}
						}
						if (contains && grid.getPawn(c2) == null)
						{
							grid.movePawn(c1, c2);
							c1 = c2;
							moveLeft--;
							display.show(grid.getGrid());
						}
						break;
					}

					case 2:
					{
						continueMove = false;
						break;
					}

					default:
					{
						display.invalidChoice();
						break;
					}
				}
				if (moveLeft == 0)
				{
					continueMove = false;
				}
			}
			wrongCoordinated = false;
		}
		else
			wrongCoordinated = true;
		return wrongCoordinated;
	}

	/**
	 * @param player
	 * @return
	 */
	private static Boolean moveProtPhos(Player player)
	{
		Integer[] c1 = new Integer[2];
		while (c1[0] == null || c1[1] == null)
		{
			c1 = display.askWhichPawnMove(player.getName(), player
					.getPlayerId(), "proteine or phospholipide");
		}
		Boolean wrongCoordinated = true;
		if (grid.getPawn(c1) != null
				&& grid.getPawn(c1).getPlayerId() == player.getPlayerId())
		{
			Pawn pawn = grid.getPawn(c1);
			if (pawn.getClass().getName().equals(
					"com.engine.pattern.pawn.Phospholipide"))
			{
				Boolean continueMove = true;
				Integer moveLeft = pawn.getMoveFn();
				while (continueMove)
				{
					Integer choice = null;
					while (choice == null)
					{
						choice = display.chooseAnAction(moveLeft);
					}
					switch (choice)
					{
						case 1:
						{
							Integer[] c2 = new Integer[2];
							while (c2[0] == null && c2[1] == null)
							{
								c2 = display.askWherePawnMove(player.getName(),
										player.getPlayerId());
							}
							ArrayList<Integer[]> possibleCells = calculPossibleCells(
									pawn, c1);
							Boolean contains = false;
							Iterator<Integer[]> cell = possibleCells.iterator();
							while (cell.hasNext())
							{
								Integer[] a = cell.next();
								if (a[0] == c2[0])
								{
									if (a[1] == c2[1])
									{
										contains = true;
										break;
									}
								}
							}
							if (contains && grid.getPawn(c2) == null)
							{
								grid.movePawn(c1, c2);
								c1 = c2;
								moveLeft--;
								if (moveLeft != 0)
								{
									display.show(grid.getGrid());
								}
							}
							else
							{
								display.invalidChoice();
							}
							break;
						}

						case 2:
						{
							continueMove = false;
							break;
						}

						default:
						{
							display.invalidChoice();
							break;
						}
					}
					if (moveLeft == 0)
					{
						continueMove = false;
					}
				}
			}
			else if (pawn.getClass().getName().equals(
					"com.engine.pattern.pawn.Proteine"))
			{
				Proteine proteine = (Proteine) pawn;
				if (proteine.getTypeProt() > 0)
				{
					Integer[] c2 = new Integer[2];
					while (c2[0] == null || c2[1] == null)
					{
						c2 = display.askWherePawnMove(player.getName(), player
								.getPlayerId());
					}
					ArrayList<Integer[]> possibleCells = calculPossibleCells(
							pawn, c1);
					Boolean contains = false;
					Iterator<Integer[]> cell = possibleCells.iterator();
					while (cell.hasNext())
					{
						Integer[] a = cell.next();
						if (a[0] == c2[0])
						{
							if (a[1] == c2[1])
							{
								contains = true;
								break;
							}
						}
					}
					if (contains
							&& grid.getPawn(c2) != null
							&& grid.getPawn(c2).getClass().getName().equals(
									"com.engine.pattern.pawn.Metabolite"))
					{
						Pawn p = grid.getPawn(c2);
						p.setOwner(player.getName());
						player.addPoint();
						display.printScore(player.getName(), player
								.getTeamNumber(), player.getScore());
						grid.removePawn(c2[1], c2[0]);
						grid.movePawn(c1, c2);
						proteine.setTypeProt(proteine.getTypeProt() - 1);
					}
					else if (contains
							&& grid.getPawn(c2) != null
							&& (grid.getPawn(c2).getClass().getName().equals(
									"com.engine.pattern.pawn.Proteine") || grid
									.getPawn(c2)
									.getClass()
									.getName()
									.equals(
											"com.engine.pattern.pawn.Phospholipide")))
					{
						grid.removePawn(c2[1], c2[0]);
						grid.movePawn(c1, c2);
					}
					else if (contains && grid.getPawn(c2) == null)
					{
						grid.movePawn(c1, c2);
					}
					else
					{
						display.invalidChoice();
					}
					wrongCoordinated = false;
				}
				else
				{
					display.invalidProt();
				}
			}
			else
			{
				display.cellEmpty(c1);
				wrongCoordinated = true;
			}
		}
		return wrongCoordinated;

	}

	/**
	 * @param computerFn
	 */
	private static void createComputerPlayer(Integer computerFn)
	{
		for (Integer i = 0; i < computerFn; i++)
		{
			Integer team = display.askPlayerTeam();
			Computer computer = new Computer(team);
			players.add(computer);
		}
	}

	/**
	 * @param humanFn
	 */
	private static void createHumanPlayer(Integer humanFn)
	{
		Integer team = null;
		String name = null;

		for (Integer i = 0; i < humanFn; i++)
		{
			name = display.askPlayerName();
			while (team == null)
			{
				team = display.askPlayerTeam();
			}
			Human human = new Human(name, team);
			players.add(human);
			team = null;

		}
	}

	/**
	 * 
	 */
	private static void printAllScore()
	{
		Iterator<Player> iterator = players.iterator();
		display.listScore();
		while (iterator.hasNext())
		{
			Player player = iterator.next();
			display.printScore(player.getName(), player.getTeamNumber(), player
					.getScore());
		}
	}

	/**
	 * 
	 */
	public static void searchMaxScore()
	{
		Iterator<Player> iterator = players.iterator();
		LinkedHashMap<String[], Integer> searchMax = new LinkedHashMap<String[], Integer>();
		Iterator<String[]> iterateur = searchMax.keySet().iterator();
		String[] clef = null;
		Integer valeur = null;
		Integer score = new Integer(0);
		while (iterator.hasNext())
		{
			Player player = iterator.next();
			if (player.getScore() > score)
			{
				searchMax = new LinkedHashMap<String[], Integer>();
				String[] id = { "", "" };
				id[0] = player.getName();
				id[1] = Integer.toString(player.getTeamNumber());
				searchMax.put(id, player.getScore());
				score = player.getScore();

			}
			else if (player.getScore() == score)
			{
				String[] id = { "", "" };
				id[0] = player.getName();
				id[1] = Integer.toString(player.getTeamNumber());
				searchMax.put(id, player.getScore());
			}
		}
		display.listWinnerScore();
		while (iterateur.hasNext())
		{
			clef = (String[]) iterateur.next();
			valeur = searchMax.get(clef);
			display.printScore(clef[0], clef[1], valeur);
		}
	}

	/**
	 * @param pawn
	 * @param c
	 * @return
	 */
	public static ArrayList<Integer[]> calculPossibleCells(Pawn pawn,
			Integer[] c)
	{

		ArrayList<Integer[]> possibleCells = new ArrayList<Integer[]>();
		Integer xAxis = c[1];
		Integer yAxis = c[0];
		Integer[] cell1 = new Integer[2];
		Integer[] cell2 = new Integer[2];
		Integer[] cell3 = new Integer[2];
		Integer[] cell4 = new Integer[2];
		Integer[] cell5 = new Integer[2];
		Integer[] cell6 = new Integer[2];
		Integer[] cell7 = new Integer[2];
		Integer[] cell8 = new Integer[2];

		if (pawn.getDownLeft())
		{
			cell1[1] = xAxis - 1;
			cell1[0] = yAxis + 1;
			possibleCells.add(cell1);
		}
		if (pawn.getLeft())
		{
			cell2[1] = xAxis - 1;
			cell2[0] = yAxis;
			possibleCells.add(cell2);
		}
		if (pawn.getUpLeft())
		{
			cell3[1] = xAxis - 1;
			cell3[0] = yAxis - 1;
			possibleCells.add(cell3);
		}
		if (pawn.getDown())
		{
			cell4[1] = xAxis;
			cell4[0] = yAxis + 1;
			possibleCells.add(cell4);
		}
		if (pawn.getRight())
		{
			cell5[1] = xAxis + 1;
			cell5[0] = yAxis;
			possibleCells.add(cell5);
		}
		if (pawn.getDownRight())
		{
			cell6[1] = xAxis + 1;
			cell6[0] = yAxis + 1;
			possibleCells.add(cell6);
		}
		if (pawn.getUp())
		{
			cell7[1] = xAxis;
			cell7[0] = yAxis - 1;
			possibleCells.add(cell7);
		}
		if (pawn.getUpRight())
		{
			cell8[1] = xAxis + 1;
			cell8[0] = yAxis - 1;
			possibleCells.add(cell8);
		}
		return possibleCells;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		start();
	}

	/**
	 * @param mode
	 */
	public static void setMode(Integer mode)
	{
		Controller.mode = mode;
	}

	/**
	 * @return
	 */
	public static Integer getMode()
	{
		return mode;
	}
}
